package nfa;

import dfa.DFADesign;
import fa.FARule;
import org.junit.jupiter.api.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.*;

/**
 * @author haoly
 * @title NFASimulationTest
 * @date 2025/4/17 19:19
 * @description NFASimulation测试类
 */
public class NFASimulationTest {
    @Test
    void testCurrentStates() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 1),
                new FARule<>(1, 'a', 2),
                new FARule<>(1, null, 2),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'b', 1),
                new FARule<>(3, null, 2)
        );

        NFARulebook<Integer> rulebook = new NFARulebook<>(rules);

        NFADesign<Integer> nfaDesign = new NFADesign<>(1, Set.of(3), rulebook);


        NFASimulation simulation = new NFASimulation(nfaDesign);


        assertEquals(Set.of(1, 2), simulation.nextState(Set.of(1, 2), 'a'));

        assertEquals(Set.of(2, 3), simulation.nextState(Set.of(1, 2), 'b'));

        assertEquals(Set.of(1, 2, 3), simulation.nextState(Set.of(2, 3), 'b'));

        assertEquals(Set.of(1, 2, 3), simulation.nextState(Set.of(1, 2, 3), 'b'));

        assertEquals(Set.of(1, 2), simulation.nextState(Set.of(1, 2, 3), 'a'));

    }

    @Test
    void testRulesFor() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 1),
                new FARule<>(1, 'a', 2),
                new FARule<>(1, null, 2),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'b', 1),
                new FARule<>(3, null, 2)
        );

        NFARulebook<Integer> rulebook = new NFARulebook<>(rules);

        NFADesign<Integer> nfaDesign = new NFADesign<>(1, Set.of(3), rulebook);


        NFASimulation simulation = new NFASimulation(nfaDesign);

        assertEquals(Set.of('a', 'b'), rulebook.alphabet());

        System.out.println(simulation.rulesFor(Set.of(1,2)));

        System.out.println(simulation.rulesFor(Set.of(2,3)));



    }

    @Test
    void testDiscoverStatesAndRules() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 1),
                new FARule<>(1, 'a', 2),
                new FARule<>(1, null, 2),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'b', 1),
                new FARule<>(3, null, 2)
        );

        NFARulebook<Integer> rulebook = new NFARulebook<>(rules);

        NFADesign<Integer> nfaDesign = new NFADesign<>(1, Set.of(3), rulebook);


        NFASimulation simulation = new NFASimulation(nfaDesign);

        Set startState = nfaDesign.toNFA().getCurrentStates();
        System.out.println(simulation.discoverStatesAndRules(Set.of(startState)));
    }

    @Test
    void testToDFADesign() {
        List<FARule<Integer>> rules = Arrays.asList(
                new FARule<>(1, 'a', 1),
                new FARule<>(1, 'a', 2),
                new FARule<>(1, null, 2),
                new FARule<>(2, 'b', 3),
                new FARule<>(3, 'b', 1),
                new FARule<>(3, null, 2)
        );

        NFARulebook<Integer> rulebook = new NFARulebook<>(rules);

        NFADesign<Integer> nfaDesign = new NFADesign<>(1, Set.of(3), rulebook);


        NFASimulation simulation = new NFASimulation(nfaDesign);

        DFADesign dfaDesign = simulation.toDFADesign();
        assertFalse(dfaDesign.accepts("aaa"));
        assertTrue(dfaDesign.accepts("aab"));
        assertTrue(dfaDesign.accepts("bbbabb"));




    }
}
